﻿/*                              
   Copyright 2011 Nils Kopal, Christopher Krüger, Simone Sauer, Dennis Nolte, Uni Duisburg-Essen

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Sharebert.LoggingLibrary;

namespace Sharebert.LinkLayerLibrary.API
{
    /// <summary>
    /// Manages the connection to other peers. IConnection should be able to open a connection to another computer
    /// or listen for new connections.
    /// An implementation of IConnection represents the link layer part of the Sharebert p2p network and 
    /// should also performs the work of the underlying layers.
    /// </summary>
    public interface IConnection
    {
        /// <summary>
        /// Opens a connection to the specified host.
        /// </summary>
        /// <param name="remoteAddress"></param>
        /// <param name="remotePort"></param>
        /// <exception cref="System.ArgumentException">remoteAddress is empty</exception>
        /// <exception cref="System.ArgumentNullException">remoteAddress is null</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">invalid port</exception>
        /// <exception cref="NetworkException">Could not connect or already connected</exception>
        void Open(string remoteAddress, int remotePort);

        /// <summary>
        /// Closes the connection.
        /// </summary>
        void Close();

        /// <summary>
        /// Listen on the specified address and port for new connections. An incoming connection will
        /// create a new thread to handle the new connection. This method is blocking.
        /// </summary>
        /// <param name="listenAddress">The IP address to listen on new connections</param>
        /// <param name="listenPort">The port to listen on</param>
        /// <param name="backlog">The backlog, which indicates the number of parallelly handled connections</param>
        /// <exception cref="System.ArgumentNullException">listenAddress is null</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">backlog must be greater than zero</exception>
        /// <exception cref="NetworkException">Error while listening</exception>
        void Listen(IPAddress listenAddress, int listenPort, uint backlog);

        /// <summary>
        /// Sends a message to the remote host.
        /// </summary>
        /// <param name="message">The message to send</param>
        /// <exception cref="System.ArgumentNullException">message is null</exception>
        /// <exception cref="NetworkException">Not connected</exception>
        void SendMessage(IMessage message);

        /// <summary>
        /// If no message will be received for the specified time in seconds, the connection will be closed 
        /// and the TimedOut event fires.
        /// </summary>
        int ReadTimeout { get; set; }

        /// <summary>
        /// If a message can not be written in the specified time in seconds, the connection will be closed 
        /// and the TimedOut event fires.
        /// </summary>
        int WriteTimeout { get; set; }

        /// <summary>
        /// The remote IP address of this connection. Will persist even if the connection is closed, timedout, etc.
        /// If no connection is established, will be set to null.
        /// </summary>
        string RemoteAddress { get; }

        /// <summary>
        /// The remote port of this connection. Will persist even if the connection is closed, timedout, etc.
        /// If no connection is established, will be set to 0.
        /// </summary>
        int RemotePort { get; }

        /// <summary>
        /// The local IP address of this connection. Will persist even if the connection is closed, timedout, etc.
        /// If no connection is established, will be set to null.
        /// </summary>
        string LocalAddress { get; }

        /// <summary>
        /// The local port of this connection. Will persist even if the connection is closed, timedout, etc.
        /// If no connection is established, will be set to 0.
        /// </summary>
        int LocalPort { get; }

        /// <summary>
        /// Issues the state of this connection.
        /// </summary>
        bool Connected { get; }

        /// <summary>
        /// The connection has timed out.
        /// </summary>
        event EventHandler<EventArgs> ConnectionTimedOut;

        /// <summary>
        /// The connection has been closed.
        /// </summary>
        event EventHandler<EventArgs> ConnectionClosed;

        /// <summary>
        /// A new client has connected. This only fires if this is a listening connection.
        /// </summary>
        event EventHandler<ConnectionEventArgs> NewConnectionEstablished;

        /// <summary>
        /// A message has been received.
        /// </summary>
        event EventHandler<MessageReceivedEventArgs> MessageReceived;
    }
}
